
#include "Wire.h"
#include "assert.h"
#include "BridgeWrapper.h"

// ============================================================================

Wire::PortPoint::PortPoint (Bridge^ bridge, int portIndex)
{
	this->bridge = bridge;
	this->portIndex = portIndex;
}

Wire::PortPoint::PortPoint (BinaryReader^ stream)
{
	int bridgeIndex = stream->ReadInt32 ();
	int portIndex = stream->ReadInt32 ();

	this->bridge = Bridge::bridges [bridgeIndex];
	this->portIndex = portIndex;
}

void Wire::PortPoint::Serialize (BinaryWriter^ bw)
{
	bw->Write (Bridge::bridges->IndexOf (this->bridge));
	bw->Write (this->portIndex);
}

// ============================================================================

Wire::FreePoint::FreePoint (float x, float y)
{
	this->x = x;
	this->y = y;
}

Wire::FreePoint::FreePoint (BinaryReader^ stream)
{
	x = stream->ReadSingle ();
	y = stream->ReadSingle ();
}

void Wire::FreePoint::Serialize (BinaryWriter^ bw)
{
	bw->Write (this->x);
	bw->Write (this->y);
}

// ============================================================================

Wire::Wire (Bridge^ startBridge, int startPortIndex, Bridge^ endBridge, int endPortIndex)
{
	this->points = gcnew List<Point^> (2);
	this->points->Add (gcnew PortPoint (startBridge, startPortIndex));
	this->points->Add (gcnew PortPoint (endBridge, endPortIndex));
}

Wire::Wire (BinaryReader^ br)
{
	int pointCount = br->ReadInt32 ();

	this->points = gcnew List<Point^> (pointCount);

	for (int i = 0; i < pointCount; i++)
	{
		Point^ point;
		char type = br->ReadSByte ();
		if (type == 0)
			point = gcnew FreePoint (br);
		else
			point = gcnew PortPoint (br);

		points->Add (point);
	}
}

void Wire::Serialize (BinaryWriter^ stream)
{
	stream->Write (points->Count);

	for (int i = 0; i < points->Count; i++)
	{
		Point^ point = points [i];
		if (point->GetType () == FreePoint::typeid)
			stream->Write ((SByte) 0);
		else
			stream->Write ((SByte) 1);

		points [i]->Serialize (stream);
	}
}

/*
void Wire::AttachPointToPort (int pointIndex, Bridge^ bridge, int portIndex)
{
	// must be an end
	assert ((pointIndex == 0) || (pointIndex == points->Count - 1));

	if (points [pointIndex]->GetType () == Wire::PortPoint::typeid)
	{
		//Wire::PortPoint^ currentPoint
	}

	// must not be currently
	assert (points [0]->GetType () == Wire::PortPoint::typeid);
}

void Wire::DetachPointFromPort (int pointIndex)
{
	assert ((pointIndex == 0) || (pointIndex == points->Count - 1));
}
*/
void Wire::Paint (Graphics^ g)
{
	Pen^ pen = wirePen;

	// If both ends are forwarding, make the wire thick.
	if ((points [0]->GetType () == Wire::PortPoint::typeid)
		&& (points [points->Count - 1]->GetType () == Wire::PortPoint::typeid))
	{
		Wire::PortPoint^ leftPortPoint = (Wire::PortPoint^) points [0];
		Wire::PortPoint^ rightPortPoint = (Wire::PortPoint^) points [points->Count - 1];

		if (leftPortPoint->bridge->ports [leftPortPoint->portIndex]->trees [CIST_INDEX]->forwarding
			&& rightPortPoint->bridge->ports [rightPortPoint->portIndex]->trees [CIST_INDEX]->forwarding)
		{
			pen = forwardingWirePen;
		}
	}

	PointF start = points [0]->GetCoords ();

	for (int i = 1; i < points->Count; i++)
	{
		PointF end = points [i]->GetCoords ();
		g->DrawLine (pen, start, end);

		Rectangle grabHandleRect ((int) ((start.X + end.X) / 2 - Wire::GrabHandleRectSize / 2),
			(int) ((start.Y + end.Y) / 2 - Wire::GrabHandleRectSize / 2),
			(int) Wire::GrabHandleRectSize,
			(int) Wire::GrabHandleRectSize);

		ControlPaint::DrawGrabHandle (g, grabHandleRect, true, true);

		start = end;
	}
}

PointF Wire::FreePoint::GetCoords ()
{
	return PointF (x, y);
}

PointF Wire::PortPoint::GetCoords ()
{
	return bridge->GetCoordsForExteriorPort (portIndex);
}

